﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda INodeList_FTP</summary>
    public class INodeList_FTP : INodeList
    {
        /// <summary>Trieda INodeComparer</summary>
        protected class INodeComparer : System.Collections.Generic.IComparer<INode>
        {
            protected delegate int OnCompare(INode N1, INode N2);
            protected OnCompare FCompareMethod; // Metoda porovnania

            /// <summary>Porovnanie podla nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_FTP_ITEM)N1.NodeData).FTP_ItemName, ((INodeData_FTP_ITEM)N2.NodeData).FTP_ItemName);
            }
            /// <summary>Porovnanie podla nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_FTP_ITEM)N1.NodeData).FTP_ItemName, ((INodeData_FTP_ITEM)N2.NodeData).FTP_ItemName);
            }
            /// <summary>Porovnanie podla pripony asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Asc(INode N1, INode N2)
            {
                int R = string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Asc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla pripony desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Desc(INode N1, INode N2)
            {
                int R = -string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Desc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla velkosti asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Asc(INode N1, INode N2)
            {
                if (((INodeData_FTP_ITEM)N1.NodeData).FTP_Size == ((INodeData_FTP_ITEM)N2.NodeData).FTP_Size) return Compare_0_Asc(N1, N2);
                return ((INodeData_FTP_ITEM)N1.NodeData).FTP_Size > ((INodeData_FTP_ITEM)N2.NodeData).FTP_Size ? 1 : -1;
            }
            /// <summary>Porovnanie podla velkosti desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Desc(INode N1, INode N2)
            {
                if (((INodeData_FTP_ITEM)N1.NodeData).FTP_Size == ((INodeData_FTP_ITEM)N2.NodeData).FTP_Size) return Compare_1_Asc(N1, N2);
                return ((INodeData_FTP_ITEM)N1.NodeData).FTP_Size > ((INodeData_FTP_ITEM)N2.NodeData).FTP_Size ? -1 : 1;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Asc(INode N1, INode N2)
            {
                int R = ((INodeData_FTP_ITEM)N1.NodeData).FTP_ModifyDate.CompareTo(((INodeData_FTP_ITEM)N2.NodeData).FTP_ModifyDate);
                if (R == 0) return Compare_0_Asc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Desc(INode N1, INode N2)
            {
                int R = -((INodeData_FTP_ITEM)N1.NodeData).FTP_ModifyDate.CompareTo(((INodeData_FTP_ITEM)N2.NodeData).FTP_ModifyDate);
                if (R == 0) return Compare_0_Desc(N1, N2);
                return R;
            }

            /// <summary>Konstruktor</summary>
            /// <param name="pCol">triediaci stlpec</param>
            /// <param name="pDirection">smer</param>
            public INodeComparer(int pCol, bool pDirection)
            {
                switch (pCol)
                {
                    case 4: if (pDirection) FCompareMethod = Compare_4_Asc; else FCompareMethod = Compare_4_Desc; break;
                    case 2: if (pDirection) FCompareMethod = Compare_2_Asc; else FCompareMethod = Compare_2_Desc; break;
                    case 1: if (pDirection) FCompareMethod = Compare_1_Asc; else FCompareMethod = Compare_1_Desc; break;
                    default: if (pDirection) FCompareMethod = Compare_0_Asc; else FCompareMethod = Compare_0_Desc; break;
                }
            }

            /// <summary>Compare metoda</summary>
            /// <param name="x">objekt 1</param>
            /// <param name="y">objekt 2</param>
            /// <returns>vysledok porovnania</returns>
            int System.Collections.Generic.IComparer<INode>.Compare(INode x, INode y)
            {
                return FCompareMethod(x, y); // Volam porovnavaciu metodu
            }
        }

        protected string FBaseServerName; // Adresa FTP servra
        protected string FRootPath; // Vzdialeny root priecinok
        protected IFTPConnectionProvider FProvider; // Poskytovatel FTP spojenia

        protected bool FExpand_Init; // Priznak inicializovaneho expandovania
        protected System.Collections.Generic.List<INode> FExpand_Dirs;
        protected System.Collections.Generic.List<INode> FExpand_Files;
        protected System.IO.StringReader FExpand_Reader;

        protected string FCopyModeBasePath; // Premenne pre copy mode
        protected IFTPConnectionProvider FCopyMode_Provider;
        protected System.Collections.Generic.List<string> FCopyMode_RootList;
        protected byte[] FCopyMode_Buffer;
        protected DateTime FCopyMode_DModify; // Datumn modifikacie suboru
        protected long FCopyMode_FileSize; // Aktualna velkost suboru
        protected string FCopyMode_CurrentFileName; // Meno aktualneho suboru

        /// <summary>Property: PasswordCacheID</summary>
        public override string PasswordCacheID
        {
            get
            {
                return FProvider == null ? "" : FProvider.PasswordCacheID;
            }
        }
        /// <summary>Property: CacheID</summary>
        public override string CacheID
        {
            get
            {
                return string.Format("{0}_{1}", ConnectionProvider, CurrentPath).ToLower();
            }
        }

        /// <summary>Zapis node do cache</summary>
        /// <param name="pNode">objekt</param>
        protected override void WriteNodeToCache(INode pNode)
        {
            if (!IsWriteCacheReady) return; // Ziadna cache?

            FCacheWriter.Write(pNode.ID);
            FCacheWriter.Write(((INodeData_FTP_ITEM)pNode.NodeData).FTP_IsDirectory);
            FCacheWriter.Write(((INodeData_FTP_ITEM)pNode.NodeData).FTP_ItemName);
            FCacheWriter.Write(((INodeData_FTP_ITEM)pNode.NodeData).FTP_ModifyDate.Ticks);
            FCacheWriter.Write(((INodeData_FTP_ITEM)pNode.NodeData).FTP_Size);
            FCacheWriter.Write(((INodeData_FTP_ITEM)pNode.NodeData).FTP_Attributes);
        }
        /// <summary>Nacitanie node z cache</summary>
        /// <returns>objekt alebo null pre koniec</returns>
        protected override bool ReadNodeFromCache(INode Result)
        {
            if (!IsReadCacheReady) return false;
            try
            {
                Result.ID = FCacheReader.ReadInt32(); // Nacitam
                Result.NodeData = new INodeData_FTP_ITEM();
                ((INodeData_FTP_ITEM)Result.NodeData).FTP_IsDirectory = FCacheReader.ReadBoolean();
                ((INodeData_FTP_ITEM)Result.NodeData).FTP_ItemName = FCacheReader.ReadString();
                ((INodeData_FTP_ITEM)Result.NodeData).FTP_ModifyDate = new DateTime(FCacheReader.ReadInt64());
                ((INodeData_FTP_ITEM)Result.NodeData).FTP_Size = FCacheReader.ReadInt64();
                ((INodeData_FTP_ITEM)Result.NodeData).FTP_Attributes = FCacheReader.ReadUInt32();
                return true; // Vsetko OK
            }
            catch
            {
                return false;
            }
        }

        /// <summary>Konstruktor</summary>
        public INodeList_FTP(string pExpandPath, int pConnectionProvider)
        {
            // Inicializacia
            ID = NODE_LIST_ID_FTP;
            FColsCount = 5;
            FEnableVisibilityMask = 0x1e; FDefVisibilityMask = 0x1f;
            FThreadExpandAvailable = true;
            FHasBackItem = true;

            IFileSystem.SplitFTPPath(pExpandPath, out FBaseServerName, out FRootPath); // Ulozim casti
            FProvider = (IFTPConnectionProvider)IApp.GlobalData.GetConnectionProvider(pConnectionProvider);
            if (FProvider != null) ConnectionProvider = FProvider.ID; // Ulozim ID providera
        }
        /// <summary>Konstruktor</summary>
        public INodeList_FTP(string pExpandPath, IFTPConnectionProvider pProvider)
        {
            // Inicializacia
            ID = NODE_LIST_ID_FTP;
            FColsCount = 5;
            FEnableVisibilityMask = 0x1e; FDefVisibilityMask = 0x1f;
            FThreadExpandAvailable = true;
            FHasBackItem = true;

            IFileSystem.SplitFTPPath(pExpandPath, out FBaseServerName, out FRootPath); // Ulozim casti
            FProvider = pProvider;
            if (FProvider != null) ConnectionProvider = FProvider.ID; // Ulozim ID providera
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_FTP_TEXT_1;
                case 1: return lang.NODE_LIST_FTP_TEXT_2;
                case 2: return lang.NODE_LIST_FTP_TEXT_3;
                case 3: return lang.NODE_LIST_FTP_TEXT_4;
                case 4: return lang.NODE_LIST_FTP_TEXT_5;
                default: return "";
            }
        }
        /// <summary>Ziskanie zarovnania stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>zarovnanie</returns>
        public override System.Windows.Forms.HorizontalAlignment GetColumnAlignment(int pIndex)
        {
            switch (pIndex)
            {
                case 2:
                    return System.Windows.Forms.HorizontalAlignment.Right;
                case 3:
                case 4:
                    return System.Windows.Forms.HorizontalAlignment.Center;
                default: return System.Windows.Forms.HorizontalAlignment.Left;
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return IFileSystem.AppendToPath("ftp://" + FBaseServerName + "/", FRootPath);
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                if (FRootPath != "") return IFileSystem.ExtractName(CurrentPath).ToLower();
                return RootKeyValue;
            }
        }
        /// <summary>Property: RootKeyValue</summary>
        public string RootKeyValue
        {
            get
            {
                return FProvider == null ? "" : FProvider.ID.ToString() + "_" + FProvider.ConnDefs.Conn_Name.ToLower();
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string ParentPath
        {
            get
            {
                return FRootPath == "" ? "web://" : IFileSystem.ExtractPath(CurrentPath);
            }
        }
        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_FTP_ITEM:
                    return ((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory;
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_FTP_ITEM: return IFileSystem.AppendToPath(CurrentPath, ((INodeData_FTP_ITEM)N.NodeData).FTP_ItemName);
                default: return "";
            }
        }
        /// <summary>Property: CanSort</summary>
        public override bool CanSort
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci je mozne podla zadaneho stlpca triedit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool IsSortColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 3:
                    return false;
                default: return true;
            }
        }
        /// <summary>Property: CanSelect</summary>
        public override bool CanSelect
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanSelectNode(INode pNode)
        {
            if (pNode == null) return false; // Ziskam platny node

            switch (pNode.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: IsCopySource</summary>
        public override bool IsCopySource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsCopySourceItem</summary>
        public override bool IsCopySourceItem(int pIndex)
        {
            if (!IsCopySource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: CanCreateFolder</summary>
        public override bool CanCreateFolder
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: CanRename</summary>
        public override bool CanRename
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti premenovania polozky</summary>
        public override bool CanRenameItem(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Chyby node?

            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: IsCopyDestination</summary>
        public override bool IsCopyDestination
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: CanDelete</summary>
        public override bool CanDelete
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: CanDeleteItem</summary>
        /// <param name="pIndex">pozicia</param>
        public override bool CanDeleteItem(int pIndex)
        {
            if (!CanDelete) return false; // Test celeho zoznamu
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: IsMoveSource</summary>
        public override bool IsMoveSource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsMoveSourceItem</summary>
        public override bool IsMoveSourceItem(int pIndex)
        {
            if (!IsMoveSource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: HasUnixAttributes</summary>
        public override bool HasUnixAttributes
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: CanChangeAttributes</summary>
        public override bool CanChangeAttributes
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti menit atributy node</summary>
        public override bool CanChangeAttributesNode(int pIndex)
        {
            if (!CanChangeAttributes) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: BasePath</summary>
        public override string BasePath
        {
            get
            {
                return "ftp://" + FBaseServerName + "/";
            }
        }
        /// <summary>Test ci musi byt subor pre prezeranie skopirovany do temp priecinku</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool NeedNodeToBeCopiedForView(int pIndex)
        {
            return true;
        }
        /// <summary>Test ci moze byt node prezerany</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeBeViewed(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_FTP_ITEM: return N.IsFile;
                default: return false;
            }
        }
        /// <summary>Test ci moze byt node editovany</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeBeEdited(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_FTP_ITEM: return N.IsFile;
                default: return false;
            }
        }
        /// <summary>Property: IsDecryptionSource</summary>
        public override bool IsDecryptionSource
        {
            get
            {
                return IsCopySource;
            }
        }
        /// <summary>Test ci je node source pre desifrovanie</summary>
        public override bool IsDecryptionSourceItem(int pIndex)
        {
            return IsCopySourceItem(pIndex);
        }
        /// <summary>Property: IsEncryptionDestination</summary>
        public override bool IsEncryptionDestination
        {
            get
            {
                return IsCopyDestination;
            }
        }

        /// <summary>Zaciatok expandovania obsahu</summary>
        /// <param name="pFilter">objekt filtra</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int BeginExpand(INodeFilters pFilter = null)
        {
            if (FProvider == null) return -1; // Neznamy provider?

            FExpand_Init = false;
            FExpand_Dirs = new System.Collections.Generic.List<INode>(); FExpand_Files = new System.Collections.Generic.List<INode>(); // Polia pre subory a priecinky
            FExpand_Reader = null;

            FState = 1; // Nastavim mode expand
            return 0;
        }
        /// <summary>Uzatvorenie aktualneho expandu</summary>
        public override void CloseExpand()
        {
            //FProvider.EndList();
            //FProvider.CloseConnection();

            // Zaradim do zoznamu
            for (int i = 0; i < FExpand_Dirs.Count; i++) AddNode(FExpand_Dirs[i]);
            for (int i = 0; i < FExpand_Files.Count; i++) AddNode(FExpand_Files[i]);

            FExpand_Dirs.Clear(); FExpand_Dirs = null;
            FExpand_Files.Clear(); FExpand_Files = null;
            FExpand_Reader = (System.IO.StringReader)ICore.DisposeObject(FExpand_Reader);

            FState = 0; // Nastavim normalny mod
        }
        /// <summary>Expandovanie dalsieho zaznamu</summary>
        /// <param name="Result">ulozeny obsah najdeneho zaznamu alebo null ak sa ma zaznam pripojit do zoznamu</param>
        /// <returns>0 - ziaden dalsi zaznam, 1 - najdeny zaznam alebo kod chyby</returns>
        public override int ExpandNext(INodeFilters pFilter = null, INode Result = null)
        {
            int R;
            try
            {
                if (!FExpand_Init)
                {
                    if (!IsReadCacheReady)
                    {
                        if (ProgressMessage != null) ProgressMessage.StringValue = lang.NODE_LIST_FTP_TEXT_10;
                        string Name, Pwd; bool AskForLogin = false;

                        Name = IApp.GlobalData.GetPassword(PasswordCacheID); // Ziskam login z cache
                        if (Name == null) // Nie je?
                        {
                            Name = FProvider.ConnDefs.Conn_LoginName; // Ziskam z prednastavenych dat
                            Pwd = FProvider.ConnDefs.Conn_LoginPwd;
                            AskForLogin = (Name.Length == 0) || (Pwd.Length == 0); // Chyba nejaka cast?
                        }
                        else // Mam z cache
                        {
                            string[] S = Name.Split(new char[] { (char)0x1 }); // Rozdelim
                            if (S.Length != 2) // Chyba?
                            {
                                Name = FProvider.ConnDefs.Conn_LoginName; // Ziskam z prednastavenych dat
                                Pwd = FProvider.ConnDefs.Conn_LoginPwd;
                                AskForLogin = (Name.Length == 0) || (Pwd.Length == 0); // Chyba nejaka cast?
                            }
                            else
                            {
                                Name = S[0]; Pwd = S[1]; // Mam login z cache
                            }
                        }

                        while (true)
                        {
                            if (AskForCredentialsEnabled) // Je povolene ziadat meno a heslo?
                            {
                                if (AskForLogin) // Mam pytat login z cache?
                                {
                                    bool WCursor = IApp.App.WaitCursor;
                                    if (WCursor) IApp.App.WaitCursor = false;
                                    if (!IApp.ShowEditor_String(lang.NODE_LIST_FTP_TEXT_12_3, lang.NODE_LIST_FTP_TEXT_12_1, ref Name, -1, false)) // Ziadam meno
                                    {
                                        if (WCursor) IApp.App.WaitCursor = true;
                                        LastError = lang.NODE_LIST_FTP_TEXT_9_2;
                                        return -1;
                                    }
                                    if (!IApp.ShowEditor_String(lang.NODE_LIST_FTP_TEXT_12_3, lang.NODE_LIST_FTP_TEXT_12_2, ref Pwd, -1, true, null, null, true)) // Ziadam heslo
                                    {
                                        if (WCursor) IApp.App.WaitCursor = true;
                                        LastError = lang.NODE_LIST_FTP_TEXT_9_2;
                                        return -1;
                                    }
                                    if (WCursor) IApp.App.WaitCursor = true;
                                }
                            }

                            R = FProvider.OpenConnect(Name, Pwd); // Otvorim spojenie
                            {
                                switch (R)
                                {
                                    case IFTPConnectionProvider.ERROR_SERVER_CONNECT: // Chyba spojenia?
                                        {
                                            FProvider.CloseConnection();
                                            LastError = lang.NODE_LIST_FTP_TEXT_9_1;
                                            return -1;
                                        }
                                    case IFTPConnectionProvider.ERROR_SERVER_BAD_LOGIN: // Chyba loginu?
                                        {
                                            FProvider.CloseConnection();
                                            if (AskForCredentialsEnabled) { AskForLogin = true; continue; }
                                            LastError = lang.NODE_LIST_FTP_TEXT_9_2;
                                            return -1;
                                        }
                                    case 0: break;
                                    default: return -1;
                                }
                            }
                            IApp.GlobalData.SavePassword(PasswordCacheID, Name + ((char)0x1).ToString() + Pwd); // Ulozim spravne meno a heslo do cache
                            FProvider.LastValidLogin = Name; FProvider.LastValidPwd = Pwd;
                            break;
                        }

                        if (ProgressMessage != null) ProgressMessage.StringValue = lang.NODE_LIST_FTP_TEXT_11;
                        if (FProvider.BeginList(FRootPath, out FExpand_Reader) != 0) // Chyba nacitania obsahu priecinku?
                        {
                            FProvider.CloseConnection();
                            return -1;
                        }
                        FProvider.EndList();
                    }
                    if ((Result == null) && (FItems.Count == 0))
                    {
                        INode N2 = new INode(); N2.ID = INode.NODE_ID_BACK_ITEM; AddNode(N2); // Vytvorim prvy back item node
                    }
                    FExpand_Init = true;
                }

                INode N = Result == null ? new INode() : Result;
                if (!IsReadCacheReady)
                {
                    string Data = FProvider.NextListItem(FExpand_Reader);
                    if (Data == null) return 0; // Koniec?

                    if (FProvider.ServerTypeLinux) // Je to z linuxu?
                    {
                        N.ID = INode.NODE_ID_FTP_ITEM;
                        N.NodeData = new INodeData_FTP_ITEM();
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory = Data[0] == 'd';
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_ItemName = Data.Substring(55).Trim();
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_Size = ICore.ToLong(Data.Substring(27, 14).Trim());
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_Attributes = ICore.StringToUnixMode(Data.Substring(1, 9));
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_ModifyDate = LinuxFTPDateTime2DateTime(Data.Substring(42, 12));
                    }
                    else
                    {
                        N.ID = INode.NODE_ID_FTP_ITEM;
                        N.NodeData = new INodeData_FTP_ITEM();
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory = Data.IndexOf("<DIR>") != -1;
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_Attributes = 0;
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_Size = ((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory ? 0 : ICore.ToLong(Data.Substring(18, 20).Trim());
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_ItemName = Data.Substring(39).Trim();
                        ((INodeData_FTP_ITEM)N.NodeData).FTP_ModifyDate = WindowsFTPDateTime2DateTime(Data.Substring(0, 18).Trim());
                    }

                    N.ConnectionProvider = FProvider.ID;
                    WriteNodeToCache(N);
                    if (Result == null)
                    {
                        if (((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                    }
                    return 1;
                }
                else // Citam obsah z cache
                {
                    if (!ReadNodeFromCache(N))
                    {
                        if (Result == null) N.Dispose();
                        return 0;
                    }
                    WriteNodeToCache(N);
                    N.ConnectionProvider = FProvider.ID;
                    if (Result == null)
                    {
                        if (((INodeData_FTP_ITEM)N.NodeData).FTP_IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                    }
                    FCachedContent = true;
                    return 1;
                }
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>Property: DeviceRootPath</summary>
        public override string DeviceRootPath
        {
            get
            {
                return "ftp://" + FBaseServerName + "/";
            }
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[2] = lang.NODE_LIST_FTP_TEXT_6;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_FTP_ITEM:
                    {
                        if (pNode.IsDirectory)
                        {
                            pNode.DisplayStrings[0] = ((INodeData_FTP_ITEM)pNode.NodeData).FTP_ItemName; // Len nazov
                            pNode.DisplayStrings[2] = lang.NODE_LIST_FTP_TEXT_7;
                            pNode.DisplayStrings[3] = ICore.UnixModeToString(((INodeData_FTP_ITEM)pNode.NodeData).FTP_Attributes);
                            pNode.DisplayStrings[4] = ICore.DateTime2Str(((INodeData_FTP_ITEM)pNode.NodeData).FTP_ModifyDate);
                            pNode.DefaultImageIndex = 0;
                        }
                        else
                        {
                            pNode.DisplayStrings[0] = pNode.NameOnly; // Len nazov
                            if (pNode.DisplayStrings[0] == "") pNode.DisplayStrings[0] = pNode.Name; else pNode.DisplayStrings[1] = pNode.Ext; // Pripona
                            pNode.DisplayStrings[2] = ICore.Size2String((ulong)((INodeData_FTP_ITEM)pNode.NodeData).FTP_Size, IApp.Settings.FileExplorer_DisplaySizeMode); // Velkost
                            pNode.DisplayStrings[3] = ICore.UnixModeToString(((INodeData_FTP_ITEM)pNode.NodeData).FTP_Attributes);
                            pNode.DisplayStrings[4] = ICore.DateTime2Str(((INodeData_FTP_ITEM)pNode.NodeData).FTP_ModifyDate);
                            pNode.DefaultImageIndex = 1;
                        }
                    } break;
            }
        }
        /// <summary>Triedenie obsahu zoznamu</summary>
        /// <param name="pColumn">stlpec</param>
        /// <param name="pAsc">smer</param>
        public override void Sort(int pColumn, bool pAsc)
        {
            int S = IsBackNode(0) ? 1 : 0; // Urcim zaciatok
            if (DirsCount > 1)
            {
                FItems.Sort(S, DirsCount, new INodeComparer(0, pAsc));
            }
            if (FilesCount > 1)
            {
                FItems.Sort(S + DirsCount, FilesCount, new INodeComparer(pColumn, pAsc));
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_FTP(CurrentPath, ConnectionProvider);
        }

        /// <summary>Vytvorenie priecinku</summary>
        /// <param name="pName">nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int CreateFolder(string pName)
        {
            string FN = FRootPath == "" ? pName : FRootPath + "/" + pName;
            int R = FProvider.CreateFolder(FN);
            switch (R)
            {
                case 0: return 0;
                case IFTPConnectionProvider.ERROR_SERVER_FILE_EXISTS: return IFileSystem.FS_ERROR_FILE_EXISTS;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vytvorenie priecinku</summary>
        /// <param name="pCurrentName">aktualny nazov</param>
        /// <param name="pNewName">novy nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int RenameFolder(string pCurrentName, string pNewName)
        {
            string F1, F2;
            IFileSystem.SplitFTPPath(pCurrentName, out F1, out F2); // Rozdelim cestu

            int R = FProvider.RenameItem(F2, pNewName);
            switch (R)
            {
                case 0: return 0;
                case IFTPConnectionProvider.ERROR_SERVER_DIRECTORY_EXISTS: return IFileSystem.FS_ERROR_DIRECTORY_EXISTS;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Premenovanie suboru</summary>
        /// <param name="pCurrentName">aktualny nazov</param>
        /// <param name="pNewName">novy nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int RenameFile(string pCurrentName, string pNewName)
        {
            string F1, F2;
            IFileSystem.SplitFTPPath(pCurrentName, out F1, out F2); // Rozdelim cestu

            int R = FProvider.RenameItem(F2, pNewName);
            switch (R)
            {
                case 0: return 0;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }

        /// <summary>Nastavenie zoznamu do modu zdroja kopirovania</summary>
        public override void BeginSourceCopyMode()
        {
            FCopyMode_Buffer = null;
            FCopyModeBasePath = CurrentPath;
            FCopyModeBasePath = IFileSystem.AppendPathSeparator(FCopyModeBasePath); // Pridam posledny oddelovac

            FCopyMode_Provider = (IFTPConnectionProvider)IApp.GlobalData.GetConnectionProvider(ConnectionProvider); // Ziskam providera
            if (FCopyMode_Provider == null) return;
            
            FCopyMode_Provider = FCopyMode_Provider.Clone(); // Vytvorim kopiu
            if (FCopyMode_Provider.OpenConnect(FCopyMode_Provider.LastValidLogin, FCopyMode_Provider.LastValidPwd) != 0) return; // Otvorim spojenie

            System.IO.StringReader R;
            if (FCopyMode_Provider.BeginList(FRootPath, out R) != 0) return; // Ziskam zoznam poloziek v roote
            using (R)
            {
                FCopyMode_RootList = new System.Collections.Generic.List<string>();
                while (true)
                {
                    string Line = FCopyMode_Provider.NextListItem(R);
                    if (Line == null) break;
                    FCopyMode_RootList.Add(Line);
                }
                FCopyMode_Provider.EndList(); // Koniec zoznamu
            }

            CopyMode_DataBuffer = core2.AllocateMemory(MAX_COPY_BUFFER_SIZE);
            FState = 2; // Nastavim stav
        }
        /// <summary>Uzatvorenie modu kopirovania</summary>
        public override void CloseCopyMode()
        {
            FCopyMode_Provider = (IFTPConnectionProvider)ICore.DisposeObject(FCopyMode_Provider);
            if (CopyMode_DataBuffer != IntPtr.Zero) core2.FreeMemory(CopyMode_DataBuffer); // Zrusim buffer
            FState = 0; // Zrusim mod
        }
        /// <summary>Vytvorenie relativnej cesty</summary>
        /// <param name="pPath">plna cesta</param>
        /// <param name="IsFolder">priznak ci to je priecinok</param>
        /// <param name="pProposal">navrh priznaku priecinku</param>
        /// <returns>relativna cesta</returns>
        public override string CopyMode_MakeRelative(string pPath, out bool IsFolder, bool pProposal = false)
        {
            IsFolder = false;

            string P = IFileSystem.AppendPathSeparator(pPath); // Pripojim separator
            if (string.Compare(FCopyModeBasePath, 0, P, 0, FCopyModeBasePath.Length, true) != 0) return ""; // Chyba?
            P = IFileSystem.DeletePathSeparator(P).Substring(FCopyModeBasePath.Length); // Ziskam relativnu cestu

            foreach (string Line in FCopyMode_RootList) // Hladam polozku v zozname
            {
                string Name;
                if (FCopyMode_Provider.ServerTypeLinux)
                {
                    IsFolder = Line[0] == 'd';
                    Name = Line.Substring(55).Trim();
                }
                else
                {
                    IsFolder = Line.IndexOf("<DIR>") != -1;
                    Name = Line.Substring(39).Trim();
                }
                if (P == Name) return P;
            }

            IsFolder = pProposal;
            return P; // Chyba hladania
        }
        /// <summary>Vytvorenie plnej cesty</summary>
        /// <param name="pPath">relativna cesta</param>
        /// <returns>plna cesta</returns>
        public override string CopyMode_MakeSourceFullPath(string pRelative)
        {
            return IFileSystem.AppendToPath(FCopyModeBasePath, pRelative);
        }
        /// <summary>Otvorenie suboroveho streamu</summary>
        /// <param name="pRelative">relativne meno</param>
        /// <param name="pInfo">informacie o subore</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int CopyMode_OpenReadFile(string pRelative, INode pInfo = null)
        {
            FCopyMode_Provider.OpenConnect();
            string FullFN = FRootPath == "" ? pRelative : FRootPath + "/" + pRelative;
            if (pInfo != null)
            {
                FCopyMode_FileSize = ((INodeData_FTP_ITEM)pInfo.NodeData).FTP_Size;
                FCopyMode_DModify = ((INodeData_FTP_ITEM)pInfo.NodeData).FTP_ModifyDate;
            }
            else
            {
                FCopyMode_FileSize = FCopyMode_Provider.GetFileSize(FullFN);
                FCopyMode_DModify = DateTime.Now;
            }
            FCopyMode_CurrentFileName = FullFN;
            return FCopyMode_Provider.OpenFileForDownload(FullFN);
        }
        /// <summary>Ziskanie dlzky aktivneho suboru</summary>
        /// <returns>dlzka</returns>
        public override long CopyMode_GetSize()
        {
            return FCopyMode_FileSize;
        }
        /// <summary>Ziskanie atributov</summary>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <returns>atributy</returns>
        public override uint CopyMode_GetAttributes()
        {
            return IWin32.FILE_ATTRIBUTE_NORMAL;
        }
        /// <summary>Ziskanie datumu zmeny</summary>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <returns>datum zmeny</returns>
        public override DateTime CopyMode_GetModifyDate()
        {
            return FCopyMode_DModify;
        }
        /// <summary>Uzatvorenie aktualne otvoreneho suboru pre citanie</summary>
        /// <param name="pDeleteAfterClose">priznak vymazania po uzatvoreni</param>
        public override void CopyMode_CloseReadFile(bool pDeleteAfterClose = false)
        {
            FCopyMode_Provider.CloseFileForDownload();
            if (pDeleteAfterClose) FCopyMode_Provider.DeleteFile(FCopyMode_CurrentFileName);
        }
        /// <summary>Vytvorenie zoznamu pre zdroj kopirovania</summary>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <returns>zoznam</returns>
        public override INodeList CopyMode_CreateSourceList(string pRelativePath)
        {
            INodeList L = new INodeList_FTP(IFileSystem.AppendToPath(FCopyModeBasePath, pRelativePath), FCopyMode_Provider);
            return L;
        }
        /// <summary>Nacitanie obsahu</summary>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <param name="pResultBuffer">vysledny buffer alebo null pre interny</param>
        /// <returns>pocet nacitanych bajtov alebo kod chyby</returns>
        public override int CopyMode_ReadFile(int pMaxLength, IntPtr pResultBuffer)
        {
            if ((FCopyMode_Buffer == null) || (FCopyMode_Buffer.Length < pMaxLength)) FCopyMode_Buffer = new byte[pMaxLength]; // Alokujem buffer
            int C = FCopyMode_Provider.DownloadFileData(FCopyMode_Buffer, pMaxLength);
            if (C < 0) return IFileSystem.FS_ERROR_UNKNOWN;
            for (int i = 0; i < C; i++) System.Runtime.InteropServices.Marshal.WriteByte(pResultBuffer, i, FCopyMode_Buffer[i]); // Skopirujem data do nativneho bufra
            return C;
        }
        /// <summary>Nastavenie zoznamu do modu zdroja kopirovania</summary>
        public override void BeginDestinationCopyMode()
        {
            FCopyModeBasePath = FRootPath;
            if (FRootPath != "") FCopyModeBasePath += "/";

            FCopyMode_Provider = (IFTPConnectionProvider)IApp.GlobalData.GetConnectionProvider(ConnectionProvider); // Ziskam providera
            if (FCopyMode_Provider == null) return;

            FCopyMode_Provider = FCopyMode_Provider.Clone(); // Vytvorim kopiu
            if (FCopyMode_Provider.OpenConnect(FCopyMode_Provider.LastValidLogin, FCopyMode_Provider.LastValidPwd) != 0) return; // Otvorim spojenie

            FState = 3; // Nastavim stav
        }
        /// <summary>Vytvorenie priecinku pri kopirovani</summary>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <param name="pAttributes">atributy</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int CopyMode_MakeFolder(string pRelativePath, uint pAttributes)
        {
            int R = FCopyMode_Provider.CreateFolder(FCopyModeBasePath + pRelativePath);
            switch (R)
            {
                case IFTPConnectionProvider.ERROR_SERVER_DIRECTORY_EXISTS:
                case 0: 
                    return 0;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Vytvorenie plnej cesty</summary>
        /// <param name="pPath">relativna cesta</param>
        /// <returns>plna cesta</returns>
        public override string CopyMode_MakeDestinationFullPath(string pRelative)
        {
            return FCopyModeBasePath + pRelative;
        }
        /// <summary>Vytvorenie suboroveho streamu pre zapis</summary>
        /// <param name="pRelative">relativne meno</param>
        /// <param name="pAttributes">atributy noveho suboru</param>
        /// <param name="pCanOverwrite">priznak moznosti prepisania existujuceho suboru</param>
        /// <param name="pCanOverwriteAttr_ReadOnly">priznak moznosti prepisania existujuceho suboru s atributom readonly</param>
        /// <param name="pCanOverwriteAttr_Hidden">priznak moznosti prepisania existujuceho suboru s atributom hidden</param>
        /// <param name="pCanOverwriteAttr_System">priznak moznosti prepisania existujuceho suboru s atributom system</param>
        /// <param name="pModifyDate">datum modifikacie</param>
        /// <param name="pNativeStream">priznak pouzitia nativneho spracovania</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int CopyMode_CreateWriteFile(string pRelative, uint pAttributes, DateTime pModifyDate, bool pCanOverwrite = false, bool pCanOverwriteAttr_ReadOnly = false, bool pCanOverwriteAttr_Hidden = false, bool pCanOverwriteAttr_System = false, bool pNativeStream = false)
        {
            FCopyMode_Provider.OpenConnect();
            string FullFN = FCopyModeBasePath + pRelative;
            int R = FCopyMode_Provider.CreateFileForUpload(FullFN, pCanOverwrite);
            switch (R)
            {
                case 0: return 0;
                case IFTPConnectionProvider.ERROR_SERVER_ACCESS_DENIED: return IFileSystem.FS_ERROR_ACCESS_DENIED;
                case IFTPConnectionProvider.ERROR_SERVER_FILE_EXISTS: return IFileSystem.FS_ERROR_FILE_EXISTS;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Uzatvorenie aktualne otvoreneho suboru pre zapis</summary>
        /// <param name="pDeleteAfterClose">priznak vymazania suboru po uzatvoreni</param>
        public override void CopyMode_CloseWriteFile(bool pDeleteAfterClose = false)
        {
            FCopyMode_Provider.CloseFileForUpload();
        }
        /// <summary>Zapisanie obsahu</summary>
        /// <param name="pBuffer">buffer</param>
        /// <param name="pStart">zaciatok</param>
        /// <param name="pLength">dlzka</param>
        /// <returns>pocet nacitanych bajtov alebo kod chyby</returns>
        public override int CopyMode_WriteFile(IntPtr pBuffer, int pStart, int pLength)
        {
            if ((FCopyMode_Buffer == null) || (FCopyMode_Buffer.Length < pLength)) FCopyMode_Buffer = new byte[pLength]; // Alokujem buffer
            for (int i = pStart, i1 = 0; i < pLength; i++, i1++) FCopyMode_Buffer[i1] = System.Runtime.InteropServices.Marshal.ReadByte(pBuffer, i); // Skopirujem data do nativneho bufra
            int C = FCopyMode_Provider.UploadFileData(FCopyMode_Buffer, pLength);
            if (C < 0) return IFileSystem.FS_ERROR_UNKNOWN;
            return 0;
        }
        /// <summary>Prerusenie aktualnej copy operacie</summary>
        public override void CopyMode_AbortOperation()
        {
            FCopyMode_Provider.AbortFileOperation();
        }
        /// <summary>Vymazanie priecinku</summary>
        /// <param name="pRelativePath">relativny nazov</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int CopyMode_DeleteFolder(string pRelativePath)
        {
            string FullFN = FRootPath == "" ? pRelativePath : FRootPath + "/" + pRelativePath;
            int R = FCopyMode_Provider.DeleteFolder(FullFN); // Volam vymazanie
            switch (R)
            {
                case 0: return 0;
                default: return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Nacitanie obsahu</summary>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <param name="pResultBuffer">vysledny buffer alebo null pre interny</param>
        /// <returns>pocet nacitanych bajtov alebo kod chyby</returns>
        public override int CopyMode_ReadFile(int pMaxLength, byte[] pResultBuffer)
        {
            int C = CopyMode_ReadFile(pMaxLength, CopyMode_DataBuffer);
            if (C <= 0) return C; // Chyba alebo koniec?

            for (int i = 0; i < C; i++) pResultBuffer[i] = System.Runtime.InteropServices.Marshal.ReadByte(CopyMode_DataBuffer, i);
            return C;
        }
        /// <summary>Vytvorenie streamu pre zapis</summary>
        /// <param name="pRelativeName">nazov</param>
        /// <param name="pCanOverwrite">priznak moznosti prepisania existujuceho suboru</param>
        /// <param name="pCanOverwriteAttr_ReadOnly">priznak moznosti prepisania existujuceho suboru s atributom readonly</param>
        /// <param name="pCanOverwriteAttr_Hidden">priznak moznosti prepisania existujuceho suboru s atributom hidden</param>
        /// <param name="pCanOverwriteAttr_System">priznak moznosti prepisania existujuceho suboru s atributom system</param>
        /// <returns>stream alebo null</returns>
        public override System.IO.Stream CopyMode_OpenStreamForRead(string pRelativeName, out int pErrorCode)
        {
            FCopyMode_Provider.OpenConnect();
            string FullFN = FRootPath == "" ? pRelativeName : FRootPath + "/" + pRelativeName;
            
            FCopyMode_FileSize = FCopyMode_Provider.GetFileSize(FullFN);
            FCopyMode_DModify = DateTime.Now;

            FCopyMode_CurrentFileName = FullFN;
            pErrorCode = FCopyMode_Provider.OpenFileForDownload(FullFN);
            if (pErrorCode != 0) return null;

            IFTPReadStream Str = new IFTPReadStream(); // Vytvorim objekt streamu
            Str.ConnProvider = FCopyMode_Provider;
            return Str;
        }
        /// <summary>Uzatvorenie streamu pre zapis</summary>
        /// <param name="pStream">stream</param>
        /// <param name="pDeleteAfterClose">priznak vymazania po uzatvoreni</param>
        public override void CopyMode_CloseStreamForRead(System.IO.Stream pStream, bool pDeleteAfterClose)
        {
            if (pStream != null)
            {
                pStream.Dispose(); pStream = null;
                FCopyMode_Provider.CloseFileForDownload();
                if (pDeleteAfterClose) FCopyMode_Provider.DeleteFile(FCopyMode_CurrentFileName);
            }
        }
        /// <summary>Vytvorenie streamu pre zapis</summary>
        /// <param name="pRelativeName">nazov</param>
        /// <param name="pCanOverwrite">priznak moznosti prepisania existujuceho suboru</param>
        /// <param name="pCanOverwriteAttr_ReadOnly">priznak moznosti prepisania existujuceho suboru s atributom readonly</param>
        /// <param name="pCanOverwriteAttr_Hidden">priznak moznosti prepisania existujuceho suboru s atributom hidden</param>
        /// <param name="pCanOverwriteAttr_System">priznak moznosti prepisania existujuceho suboru s atributom system</param>
        /// <returns>stream alebo null</returns>
        public override System.IO.Stream CopyMode_CreateStreamForWrite(string pRelativeName, out int pErrorCode, bool pCanOverwrite = false, bool pCanOverwriteAttr_ReadOnly = false, bool pCanOverwriteAttr_Hidden = false, bool pCanOverwriteAttr_System = false)
        {
            FCopyMode_Provider.OpenConnect();
            string FullFN = FCopyModeBasePath + pRelativeName;
            int R = FCopyMode_Provider.CreateFileForUpload(FullFN, pCanOverwrite);
            switch (R)
            {
                case 0: break;
                case IFTPConnectionProvider.ERROR_SERVER_ACCESS_DENIED: { pErrorCode = IFileSystem.FS_ERROR_ACCESS_DENIED; return null; }
                case IFTPConnectionProvider.ERROR_SERVER_FILE_EXISTS: { pErrorCode = IFileSystem.FS_ERROR_FILE_EXISTS; return null; }
                default: { pErrorCode = IFileSystem.FS_ERROR_UNKNOWN; return null; }
            }

            pErrorCode = 0;
            IFTPWriteStream Str = new IFTPWriteStream(); Str.ConnProvider = FCopyMode_Provider;
            return Str;
        }
        /// <summary>Uzatvorenie streamu pre zapis</summary>
        /// <param name="pStream">stream</param>
        /// <param name="pDeleteAfterClose">priznak vymazania po uzatvoreni</param>
        public override void CopyMode_CloseStreamForWrite(System.IO.Stream pStream, bool pDeleteAfterClose)
        {
            if (pStream != null)
            {
                pStream.Dispose(); pStream = null;
                FCopyMode_Provider.CloseFileForUpload();
            }
        }

        /// <summary>Spustenie mazania zaznamov</summary>
        /// <param name="pItems">zoznam objektov</param>
        /// <param name="pProgressForm">progress okno</param>
        /// <param name="pStatData">statisticke data pre vypocet stavu</param>
        public override bool Run_DeleteItems(System.Collections.Generic.List<string> pItems, IFileExplorer_ProgressForm_DeleteItems pProgressForm = null, IComputeOccupiedSpaceData pStatData = null)
        {
            IConfirmationFlags Flags = new IConfirmationFlags(); // Priznaky potvrdeni uzivatela

            FCopyMode_Provider = (IFTPConnectionProvider)IApp.GlobalData.GetConnectionProvider(ConnectionProvider); // Ziskam providera
            if (FCopyMode_Provider == null) return false;

            FCopyMode_Provider = FCopyMode_Provider.Clone(); // Vytvorim kopiu
            if (FCopyMode_Provider.OpenConnect(FCopyMode_Provider.LastValidLogin, FCopyMode_Provider.LastValidPwd) != 0) return false; // Otvorim spojenie

            using (FCopyMode_Provider)
            {
                foreach (string FN in pItems) // Vsetky polozky
                {
                    string F1, F2;
                    if (!IFileSystem.SplitFTPPath(FN, out F1, out F2)) continue; // Rozdelim plnu cestu

                    int R = FCopyMode_Provider.GetObjectType(F2);
                    switch (R)
                    {
                        case 0:
                            {
                                if (DeleteNodeDirectory(F2, Flags, pProgressForm) == -1) return false;
                            } break;
                        case 1:
                            {
                                if (DeleteNodeFile(F2, Flags, pProgressForm) == -1) return false;
                            } break;
                    }
                }
            }
            return true; // Vsetko OK
        }
        /// <summary>Vymazanie suboru</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pFlags">objekt volieb</param>
        /// <param name="pProgressForm">formular pre progress</param>
        /// <returns>0 - OK, 1 - preskocene, -1 - uzivatelsky prerusene</returns>
        protected int DeleteNodeFile(string pName, IConfirmationFlags pFlags, IFileExplorer_ProgressForm_DeleteItems pProgressForm = null)
        {
            if (pFlags.DeleteErrorFile != IConfirmationFlags.DELETE_ERROR_SKIP_ALL) pFlags.DeleteErrorFile = -1;
            if ((pFlags.DeleteReadOnlyFile != IConfirmationFlags.DELETE_READ_ONLY_YES_ALL) && (pFlags.DeleteReadOnlyFile != IConfirmationFlags.DELETE_READ_ONLY_SKIP_ALL)) pFlags.DeleteReadOnlyFile = -1;
            if ((pFlags.DeleteSystemFile != IConfirmationFlags.DELETE_SYSTEM_YES_ALL) && (pFlags.DeleteSystemFile != IConfirmationFlags.DELETE_SYSTEM_SKIP_ALL)) pFlags.DeleteSystemFile = -1;

            while (true)
            {
                if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return -1;
                int R = FCopyMode_Provider.DeleteFile(pName); // Volam mazanie suboru
                switch (R)
                {
                    case 0:
                        {
                            if (pProgressForm != null) pProgressForm.AddFile();
                            return 0; // Vsetko OK
                        }
                    default:
                        {
                            if (pProgressForm == null) return 1; // Nie je form?
                            switch (pFlags.DeleteErrorFile)
                            {
                                case IConfirmationFlags.DELETE_ERROR_SKIP:
                                case IConfirmationFlags.DELETE_ERROR_SKIP_ALL:
                                    return 1;
                                default:
                                    {
                                        if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_19_7_1, pName), lang.FILE_EXPLORER_TEXT_19_7_2, lang.FILE_EXPLORER_TEXT_19_7_3, ref pFlags.DeleteErrorFile)) return -1;
                                    } break;
                            }
                        } break;
                }
            }
        }
        /// <summary>Vymazanie priecinku</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pFlags">objekt volieb</param>
        /// <param name="pProgressForm">formular pre progress</param>
        /// <returns>0 - OK, 1 - preskocene, -1 - uzivatelsky prerusene</returns>
        protected int DeleteNodeDirectory(string pName, IConfirmationFlags pFlags, IFileExplorer_ProgressForm_DeleteItems pProgressForm = null)
        {
            if ((pFlags.DeleteNotEmptyFolder != IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_SKIP_ALL) && (pFlags.DeleteNotEmptyFolder != IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_YES_ALL)) pFlags.DeleteNotEmptyFolder = -1;

            while (true)
            {
                int R = FCopyMode_Provider.DeleteFolder(pName); // Mazem priecinok
                if (R == 0)
                {
                    if (pProgressForm != null) pProgressForm.AddDir();
                    return 0; // OK?
                }

                if (R == IFTPConnectionProvider.ERROR_SERVER_DIR_NOT_EMPTY) // Nie je prazdny?
                {
                    while (true)
                    {
                        switch (pFlags.DeleteNotEmptyFolder)
                        {
                            case IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_YES:
                            case IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_YES_ALL:
                                break;
                            case IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_SKIP:
                            case IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_SKIP_ALL:
                                return 1;
                            default:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_19_10_1, pName), lang.FILE_EXPLORER_TEXT_19_10_2, lang.FILE_EXPLORER_TEXT_19_10_3, ref pFlags.DeleteNotEmptyFolder)) return -1;
                                } break;
                        }
                        if (pFlags.DeleteNotEmptyFolder <= IConfirmationFlags.DELETE_NOT_EMPTY_FOLDER_YES_ALL) break;
                    }
                    break; 
                }

                if (pProgressForm == null) return 1; // Nie je form?
                switch (pFlags.DeleteErrorFolder)
                {
                    case IConfirmationFlags.DELETE_ERROR_SKIP:
                    case IConfirmationFlags.DELETE_ERROR_SKIP_ALL:
                        return 1;
                    default:
                        {
                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_19_11_1, pName), lang.FILE_EXPLORER_TEXT_19_11_2, lang.FILE_EXPLORER_TEXT_19_11_3, ref pFlags.DeleteErrorFolder)) return -1;
                        } break;
                }
            }

            System.IO.StringReader Reader;
            if (FCopyMode_Provider.BeginList(pName, out Reader) != 0) return 1; // Nacitam obsah
            FCopyMode_Provider.EndList();

            using (Reader)
            {
                while (true)
                {
                    string Line = Reader.ReadLine();
                    if (Line == null) break;

                    bool IsDir; string Name;
                    if (FCopyMode_Provider.ServerTypeLinux) // Dekodujem priznak priecinku a nazov
                    {
                        IsDir = Line[0] == 'd';
                        Name = pName + "/" + Line.Substring(55).Trim();
                    }
                    else
                    {
                        IsDir = Line.IndexOf("<DIR>") != -1;
                        Name = pName + "/" + Line.Substring(39).Trim();
                    }

                    if (IsDir)
                    {
                        if (DeleteNodeDirectory(Name, pFlags, pProgressForm) == -1) return -1; // Mazem podadresar
                    }
                    else
                    {
                        if (DeleteNodeFile(Name, pFlags, pProgressForm) == -1) return -1; // Mazem subor
                    }
                }
            }

            int R1 = FCopyMode_Provider.DeleteFolder(pName); // Mazem priecinok
            if (R1 == 0)
            {
                if (pProgressForm != null) pProgressForm.AddDir();
                return 0; // OK?
            }
            return 1;
        }

        /// <summary>Spustenie procesu klonovania suboru</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pNewName">novy nazov</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public override bool Run_CloneFile(string pName, string pNewName, IFileExplorer_ProgressForm_CloneFile pProgressForm = null)
        {
            using (INodeList_FTP SourceList = new INodeList_FTP(CurrentPath, ConnectionProvider))
            {
                SourceList.BeginSourceCopyMode();
                if (SourceList.FState != 2) return false;

                bool IsFolder;
                string RelFN = SourceList.CopyMode_MakeRelative(pName, out IsFolder);
                if (string.IsNullOrEmpty(RelFN)) return false;

                System.IO.FileStream OutputFile; // Cielovy subor
                int R;
                bool DeleteResult = false;

                try
                {
                    while (true) // Otvorim zdrojovy subor
                    {
                        if (SourceList.CopyMode_OpenReadFile(RelFN, null) == 0) break;
                        if (pProgressForm != null)
                        {
                            R = 0;
                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_38_5_1, pName), lang.FILE_EXPLORER_TEXT_38_5_2, lang.FILE_EXPLORER_TEXT_38_5_3, ref R)) return false; // Opytam sa na zopakovanie
                        }
                        else return false;
                    }

                    while (true) // Vytvorim cielovy subor
                    {
                        try
                        {
                            OutputFile = new System.IO.FileStream(pNewName, System.IO.FileMode.Create, System.IO.FileAccess.Write);
                            break;
                        }
                        catch
                        {
                            if (pProgressForm != null)
                            {
                                R = 0;
                                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_38_6_1, pNewName), lang.FILE_EXPLORER_TEXT_38_6_2, lang.FILE_EXPLORER_TEXT_38_6_3, ref R))
                                {
                                    SourceList.CopyMode_AbortOperation();
                                    SourceList.CopyMode_CloseReadFile(false);
                                    return false; // Opytam sa na zopakovanie
                                }
                            }
                            else
                            {
                                SourceList.CopyMode_AbortOperation();
                                SourceList.CopyMode_CloseReadFile(false);
                                return false;
                            }
                        }
                    }

                    int C;
                    using (OutputFile)
                    {
                        byte[] Buffer = new byte[MAX_COPY_BUFFER_SIZE];
                        while (true)
                        {
                            if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) // Prerusenie?
                            {
                                DeleteResult = true;
                                SourceList.CopyMode_AbortOperation();
                                break;
                            }
                            while (true) // Nacitam data
                            {
                                C = SourceList.CopyMode_ReadFile(MAX_COPY_BUFFER_SIZE, Buffer);
                                if (C >= 0) break; // Nie je chyba?

                                R = 0;
                                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_38_7_1, pName), lang.FILE_EXPLORER_TEXT_38_7_2, lang.FILE_EXPLORER_TEXT_38_7_3, ref R)) // Opytam sa na zopakovanie
                                {
                                    DeleteResult = true;
                                    C = 0;
                                    SourceList.CopyMode_AbortOperation();
                                    break;
                                }
                            }
                            if (C == 0) break; // Koniec?

                            while (true) // Zapisem data
                            {
                                try
                                {
                                    OutputFile.Write(Buffer, 0, C);
                                    break;
                                }
                                catch
                                {
                                    R = 0;
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_38_8_1, pNewName), lang.FILE_EXPLORER_TEXT_38_8_2, lang.FILE_EXPLORER_TEXT_38_8_3, ref R)) // Opytam sa na zopakovanie
                                    {
                                        DeleteResult = true;
                                        SourceList.CopyMode_AbortOperation();
                                        break;
                                    }
                                }
                            }

                            if (pProgressForm != null) pProgressForm.AddProcessedData(C); // Aktualizujem stav
                        }
                    }

                    if (DeleteResult)
                    {
                        IFileSystem.DeleteFile(pNewName, true, true, true); // Mam vymazat vysledok?
                        SourceList.CopyMode_CloseReadFile(false);
                        return false;
                    }
                    else
                    {
                        uint Attr;
                        DateTime D1, D2, D3;
                        if (IFileSystem.GetAttributes(pName, out Attr, out D1, out D2, out D3) == 0) IFileSystem.SetAttributes(pNewName, Attr, D1, D2, D3); // Nastavim atributy
                    }

                    return true;
                }
                catch
                {
                    return false; // Chyba
                }
            }
        }

        /// <summary>Spustenie zmeny atributov zaznamov</summary>
        /// <param name="pChangeData">data pre zmenu</param>
        /// <param name="pItems">zoznam objektov</param>
        /// <param name="pProgressForm">progress okno</param>
        /// <param name="pStatData">statisticke data pre vypocet stavu</param>
        public override bool Run_ChangeItemsAttributes(IAttributeChangeDataObject pChangeData, System.Collections.Generic.List<string> pItems, IFileExplorer_ProgressForm_ChangeItemsAttributes pProgressForm = null, IComputeOccupiedSpaceData pStatData = null)
        {
            foreach (string FN in pItems) // Vsetky polozky
            {
                if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false; // Prerusenie?

                string F1, F2;
                if (!IFileSystem.SplitFTPPath(FN, out F1, out F2)) continue; // Rozdelim plnu cestu

                int R = FProvider.GetObjectType(F2); // Ziskam typ objektu
                if (R == -1) continue; // Chyba?

                if (FProvider.SetAttributes(F2, pChangeData.UnixAttributes) != 0) continue;

                if (R == 0)
                {
                    if (pProgressForm != null) pProgressForm.AddDir();
                }
                if (R == 1)
                {
                    if (pProgressForm != null) pProgressForm.AddFile();
                }
            }
            return true; // Vsetko OK
        }

        /// <summary>Prevod linuxovskeho datumu a casu na DateTime</summary>
        /// <param name="pValue">vstup</param>
        /// <returns>vysledok</returns>
        public static DateTime LinuxFTPDateTime2DateTime(string pValue)
        {
            try
            {
                string M1 = pValue.Substring(0, 3).ToLower();
                int M = 1;
                switch (M1)
                {
                    case "jan": M = 1; break;
                    case "feb": M = 2; break;
                    case "mar": M = 3; break;
                    case "apr": M = 4; break;
                    case "may": M = 5; break;
                    case "jun": M = 6; break;
                    case "jul": M = 7; break;
                    case "aug": M = 8; break;
                    case "sep": M = 9; break;
                    case "oct": M = 10; break;
                    case "nov": M = 11; break;
                    case "dec": M = 12; break;
                }
                int D = ICore.ToInt(pValue.Substring(4, 2).Trim());
                int Y = DateTime.Now.Year;
                int H = 0; int Min = 0;

                M1 = pValue.Substring(7);
                int I = M1.IndexOf(':');
                if (I == -1) // Rok
                {
                    Y = ICore.ToInt(M1.Trim());
                }
                else // Cas
                {
                    H = ICore.ToInt(M1.Substring(0, 2).Trim());
                    Min = ICore.ToInt(M1.Substring(I + 1).Trim());
                }
                return new DateTime(Y, M, D, H, Min, 0);
            }
            catch
            {
                return DateTime.Now;
            }
        }
        /// <summary>Prevod linuxovskeho datumu a casu na DateTime</summary>
        /// <param name="pValue">vstup</param>
        /// <returns>vysledok</returns>
        public static DateTime WindowsFTPDateTime2DateTime(string pValue)
        {
            try
            {
                int M = ICore.ToInt(pValue.Substring(0, 2));
                int D = ICore.ToInt(pValue.Substring(3, 2));
                int Y = ICore.ToInt(pValue.Substring(6, 2));
                if (Y <= DateTime.Now.Year - 2000) Y += 2000; // Urcim rok
                else Y += 1900;
                int H = ICore.ToInt(pValue.Substring(10, 2));
                int Min = ICore.ToInt(pValue.Substring(13, 2));
                if (pValue.Substring(15, 2).ToLower() == "pm") H += H == 12 ? 0 : 12;
                return new DateTime(Y, M, D, H, Min, 0);
            }
            catch
            {
                return DateTime.Now;
            }
        }
    }

    /// <summary>Trieda IFTPReadStream</summary>
    public class IFTPReadStream : System.IO.Stream
    {
        public IFTPConnectionProvider ConnProvider; // Spojenie

        /// <summary>Property: CanRead</summary>
        public override bool CanRead
        {
            get { return true; }
        }
        /// <summary>Property: CanWrite</summary>
        public override bool CanWrite
        {
            get { return false; }
        }
        /// <summary>Property: CanSeek</summary>
        public override bool CanSeek
        {
            get { return false; }
        }
        /// <summary>Property: Length</summary>
        public override long Length
        {
            get { return 0; }
        }
        /// <summary>Property: Position</summary>
        public override long Position
        {
            get { return 0; }
            set
            {
            }
        }

        /// <summary>Metoda: Flush</summary>
        public override void Flush()
        {
        }
        /// <summary>Metoda: Seek</summary>
        /// <param name="offset">offset</param>
        /// <param name="origin">zaciatok posunu</param>
        /// <returns>vysledok</returns>
        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            return 0;
        }
        /// <summary>Metoda: SetLength</summary>
        /// <param name="value">hodnota</param>
        public override void SetLength(long value)
        {
        }
        /// <summary>Metoda: Read</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        /// <returns>pocet nacitanych bajtov</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            int C = ConnProvider.DownloadFileData(buffer, count, offset); ;
            if (C >= 0) return C;
            throw new System.IO.IOException();
        }
        /// <summary>Metoda: Write</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        public override void Write(byte[] buffer, int offset, int count)
        {
        }

        /// <summary>Konstruktor</summary>
        public IFTPReadStream()
        {
        }
        /// <summary>Dispose metoda</summary>
        /// <param name="disposing">parameter</param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing); // Volam predchodcu
        }
    }

    /// <summary>Trieda IFTPWriteStream</summary>
    public class IFTPWriteStream : System.IO.Stream
    {
        public IFTPConnectionProvider ConnProvider; // Spojenie

        /// <summary>Property: CanRead</summary>
        public override bool CanRead
        {
            get { return false; }
        }
        /// <summary>Property: CanWrite</summary>
        public override bool CanWrite
        {
            get { return true; }
        }
        /// <summary>Property: CanSeek</summary>
        public override bool CanSeek
        {
            get { return false; }
        }
        /// <summary>Property: Length</summary>
        public override long Length
        {
            get { return 0; }
        }
        /// <summary>Property: Position</summary>
        public override long Position
        {
            get { return 0; }
            set
            {
            }
        }

        /// <summary>Metoda: Flush</summary>
        public override void Flush()
        {
        }
        /// <summary>Metoda: Seek</summary>
        /// <param name="offset">offset</param>
        /// <param name="origin">zaciatok posunu</param>
        /// <returns>vysledok</returns>
        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            return 0;
        }
        /// <summary>Metoda: SetLength</summary>
        /// <param name="value">hodnota</param>
        public override void SetLength(long value)
        {
        }
        /// <summary>Metoda: Read</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        /// <returns>pocet nacitanych bajtov</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            return 0;
            //int C = ConnProvider.DownloadFileData(buffer, count, offset); ;
            //if (C >= 0) return C;
            //throw new System.IO.IOException();
        }
        /// <summary>Metoda: Write</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        public override void Write(byte[] buffer, int offset, int count)
        {
            int C = ConnProvider.UploadFileData(buffer, count, offset);
            if (C < 0) throw new System.IO.IOException();
        }

        /// <summary>Konstruktor</summary>
        public IFTPWriteStream()
        {
        }
        /// <summary>Dispose metoda</summary>
        /// <param name="disposing">parameter</param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing); // Volam predchodcu
        }
    }
}
